`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/06 19:20:36
// Design Name: 
// Module Name: SYC_FIFO
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module SYC_FIFO #(parameter FIFO_PTR = 2, FIFO_DEPTH = 3, FIFO_WIDTH = 512)(
    input fifo_clk,
    input fifo_rst_n,
    input fifo_wren,
    input [FIFO_WIDTH-1:0] fifo_wrdata,
    input fifo_rden,
    output reg [FIFO_WIDTH-1:0] fifo_rdata,
    output reg fifo_full,
    output reg fifo_empty
    );
   
localparam MAX_ADDR = FIFO_DEPTH - 1;

reg [FIFO_PTR-1:0] wr_ptr, wr_ptr_next;
reg [FIFO_PTR-1:0] rd_ptr, rd_ptr_next;
reg [FIFO_PTR:0] num_entries, num_entries_next;
wire fifo_empty_next, fifo_full_next;


//write pointer update logic *****************************************
always @(*) begin
    wr_ptr_next = wr_ptr;
    if(fifo_wren) begin
        if(wr_ptr == MAX_ADDR)
            wr_ptr_next = 'd0;
        else
            wr_ptr_next = wr_ptr + 1 ;
    end
end

//read pointer update logic *******************************************
always @(*) begin
    rd_ptr_next = rd_ptr;
    if(fifo_rden) begin
        if(rd_ptr == MAX_ADDR)
            rd_ptr_next = 'd0;
        else
            rd_ptr_next = rd_ptr + 1;
    end
end

//calculate number of occupied entries in the FIFO********************
always @(*) begin
    num_entries_next = num_entries;
    if(fifo_wren && fifo_rden)
        num_entries_next = num_entries;
    else if(fifo_wren)
        num_entries_next = num_entries + 1'b1;
    else if(fifo_rden)
        num_entries_next = num_entries - 1'b1;
end

//full and empty flag update logic**************************************
assign fifo_empty_next = num_entries_next == 'd0;
assign fifo_full_next = num_entries_next == FIFO_DEPTH;

// register update *****************************************************
always @(posedge fifo_clk ) begin
    if(!fifo_rst_n) begin
        wr_ptr <= 'b0;
        rd_ptr <= 'b0;
        num_entries <= 'b0;
        fifo_empty <= 1'b1;
        fifo_full <= 1'b0;
    end
    else begin
        wr_ptr <= wr_ptr_next;
        rd_ptr <= rd_ptr_next;
        num_entries <= num_entries_next;
        fifo_empty <= fifo_empty_next;
        fifo_full <= fifo_full_next;
    end
end

//RAM VERILOG MODLE **************************************************
reg [FIFO_WIDTH-1:0] mem [0:FIFO_DEPTH-1];
//read
//always @(posedge fifo_clk) begin
//    if(!fifo_rst_n)
//        fifo_rdata <= 'b0;
//    else if(fifo_rden==1'b1)
//        fifo_rdata <= mem[rd_ptr];
//end
always @(*) begin
    fifo_rdata = 'b0;
    if(fifo_rden==1'b1)
        fifo_rdata = mem[rd_ptr];
end
//write
integer i;
always @(posedge fifo_clk) begin
    if(!fifo_rst_n)
        for(i = 0; i < FIFO_DEPTH; i= i+1) begin
            mem[i] <= 0;
        end
    else if(fifo_wren)
        mem[wr_ptr] <= fifo_wrdata;
end




endmodule //SYC_FIFO
    

